using System;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.Serialization;
using System.Security.Permissions;

namespace DDotNet.Data.BusinessObjects.Core
{
    /// <summary>
    /// This exception is returned for any errors occuring
    /// during the server-side DataPortal invocation.
    /// </summary>
    [SuppressMessage("Microsoft.Design", "CA1032:ImplementStandardExceptionConstructors")]
    [Serializable()]
    public class DataPortalException : Exception
    {
        private object _businessObject;
        private string _innerStackTrace;

        /// <summary>
        /// Returns a reference to the business object
        /// from the server-side DataPortal.
        /// </summary>
        /// <remarks>
        /// Remember that this object may be in an invalid
        /// or undefined state. This is the business object
        /// (and any child objects) as it existed when the
        /// exception occured on the server. Thus the object
        /// state may have been altered by the server and
        /// may no longer reflect data in the database.
        /// </remarks>
        public object BusinessObject
        {
            get { return _businessObject; }
        }

        /// <summary>
        /// Gets the original server-side exception.
        /// </summary>
        /// <returns>An exception object.</returns>
        /// <remarks>
        /// When an exception occurs in business code behind
        /// the data portal, it is wrapped in a 
        /// <see cref="Csla.Server.DataPortalException"/>, which 
        /// is then wrapped in a 
        /// <see cref="Csla.DataPortalException"/>. This property
        /// unwraps and returns the original exception 
        /// thrown by the business code on the server.
        /// </remarks>
        public Exception BusinessException
        {
            get { return this.InnerException.InnerException; }
        }

        /// <summary>
        /// Get the combined stack trace from the server
        /// and client.
        /// </summary>
        [
            SuppressMessage("Microsoft.Globalization", "CA1305:SpecifyIFormatProvider",
                MessageId = "System.String.Format(System.String,System.Object,System.Object,System.Object)")]
        public override string StackTrace
        {
            get { return String.Format("{0}{1}{2}", _innerStackTrace, Environment.NewLine, base.StackTrace); }
        }

        public DataPortalException(string message, object businessObject)
            : base(message)
        {
            _innerStackTrace = String.Empty;
            _businessObject = businessObject;
        }

        public DataPortalException(string message, Exception ex, object businessObject)
            : base(message, ex)
        {
            _innerStackTrace = ex.StackTrace;
            _businessObject = businessObject;
        }

        protected DataPortalException(SerializationInfo info, StreamingContext context)
            : base(info, context)
        {
            _businessObject = info.GetValue("_businessObject", typeof (object));
            _innerStackTrace = info.GetString("_innerStackTrace");
        }

        [SuppressMessage("Microsoft.Design", "CA1062:ValidateArgumentsOfPublicMethods")]
        [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
        [SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.SerializationFormatter)]
        public override void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            base.GetObjectData(info, context);
            info.AddValue("_businessObject", _businessObject);
            info.AddValue("_innerStackTrace", _innerStackTrace);
        }
    }
}